日志源解析|K8s 集群部署 CLS 日志服务原理及场景实现
kahing,腾讯云CLS产品经理,负责CLS云原生日志的云产品接入工作。
willyi,腾讯云高级开发工程师,负责CLS云原生日志服务云原生生态建设,致力于大规模云原生设施的落地和实践工作。
简介
什么是CLS 日志服务?
腾讯云日志服务(Cloud Log Service,CLS)是腾讯云提供的一站式日志服务平台,提供了从日志采集、日志存储到日志检索,图表分析、监控告警、日志投递等多项服务,协助用户通过日志来解决业务运维、服务监控、日志审计等场景问题。
CLS 日志服务:https://cloud.tencent.com/product/cls
什么是TKE 容器服务?
腾讯云容器服务(Tencent Kubernetes Engine,TKE)是基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,您可以在托管的云服务器实例集群上轻松运行应用程序。
TKE 容器服务:https://cloud.tencent.com/product/tke
前提条件
Kubernetes 1.10 及以上版本集群 开通日志服务, 创建日志集与日志主题, 并获取日志主题ID(topicId),详细配置请参见[2]创建日志主题 文档 获取日志主题所在地域的域名(CLS_HOST),详细CLS域名列表请参见 [3]可用地域 文档 获取访问CLS侧鉴权所需的API密钥ID(TmpSecretId)以及API密钥Key(TmpSecretKey),请前往 [4]API密钥管理 查看
K8s日志采集原理
K8s集群上部署日志采集主要涉及Log-Provisoner,Log-Agent,LogListener三个组件,以及一个LogConfig采集配置。
LogConfig:日志采集配置,定义了日志从哪里被采集, 采集后如何解析, 解析后投递至CLS侧的哪个日志主题 Log-Provisoner:将LogConfig中定义日志采集配置信息同步至CLS侧 Log-Agent:监听LogConfig和节点上容器的变化, 动态计算容器中的日志文件在节点宿主机上的实际位置 LogListener:采集节点宿主机上的相应日志文件内容,解析并上传至CLS侧
部署步骤
定义LogConfig资源类型
定义LogConfig对象
创建LogConfig对象
配置CLS鉴权ConfigMap
部署cls-provisione
部署log-agent与loglistener
定义LogConfig资源类型
# wget https://mirrors.tencent.com/install/cls/k8s/CRD.yaml
# kubectl create -f /usr/local/CRD.yaml
定义LogConfig对象
# wget https://mirrors.tencent.com/install/cls/k8s/LogConfig.yaml
LogConfig.yaml声明文件主要分为两个部分:
clsDetail:定义日志解析格式,以及目标日志主题ID(topicId) inputDetail:定义采集日志源,即日志从哪里被采集
注意:需将clsDetail中的topicId项配置为您创建的日志主题ID
日志解析格式
单行全文格式 多行全文格式 完全正则格式 JSON格式 分隔符格式
单行全文格式
Tue Jan 22 12:08:15 CST 2019 Installed: libjpeg-turbo-static-1.2.90-6.el7.x86_64
LogConfig配置参考示例如下:
apiVersion: cls.cloud.tencent.com/v1
kind: LogConfig
spec:
clsDetail:
topicId: xxxxxx-xx-xx-xx-xxxxxxxx
# 单行日志
logType: minimalist_log
采集到日志服务的数据为:
__CONTENT__:Tue Jan 22 12:08:15 CST 2019 Installed: libjpeg-turbo-static-1.2.90-6.el7.x86_64
多行全文格式
多行全文日志是指一条完整的日志数据可能跨占多行(例如 Java stacktrace)。在这种情况下,以换行符\n 为日志的结束标识符就显得有些不合理,为了能让日志系统明确区分开每条日志,采用首行正则的方式进行匹配,当某行日志匹配上预先设置的正则表达式,就认为是一条日志的开头,而下一个行首出现作为该条日志的结束标识符。
多行全文也会设置一个默认的键值__CONTENT__,但日志数据本身不再进行日志结构化处理,也不会提取日志字段,日志属性的时间项由日志采集的时间决定。
2019-12-15 17:13:06,043 [main] ERROR com.test.logging.FooFactory:
java.lang.NullPointerException
at com.test.logging.FooFactory.createFoo(FooFactory.java:15)
at com.test.logging.FooFactoryTest.test(FooFactoryTest.java:11)
LogConfig配置的参考如下:
apiVersion: cls.cloud.tencent.com/v1
kind: LogConfig
spec:
clsDetail:
topicId: xxxxxx-xx-xx-xx-xxxxxxxx
# 多行日志
logType: multiline_log
extractRule:
# 只有以日期时间开头的行才被认为是新一条日志的开头,否则就添加换行符\n并追加到当前日志的尾部
beginningRegex: \d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2},\d{3}\s.+
采集到日志服务的数据为:
__CONTENT__:2019-12-15 17:13:06,043 [main] ERROR com.test.logging.FooFactory:\njava.lang.NullPointerException\n at com.test.logging.FooFactory.createFoo(FooFactory.java:15)\n at com.test.logging.FooFactoryTest.test(FooFactoryTest.java:11)
单行-完全正则格式
10.135.46.111 - - [22/Jan/2019:19:19:30 +0800] "GET /my/course/1 HTTP/1.1" 127.0.0.1 200 782 9703 "http://127.0.0.1/course/explore?filter%5Btype%5D=all&filter%5Bprice%5D=all&filter%5BcurrentLevelId%5D=all&orderBy=studentNum" "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0" 0.354 0.354
LogConfig配置的参考如下:
apiVersion: cls.cloud.tencent.com/v1
kind: LogConfig
spec:
clsDetail:
topicId: xxxxxx-xx-xx-xx-xxxxxxxx
# 完全正则格式
logType: fullregex_log
extractRule:
# 正则表达式,会根据()捕获组提取对应的value
logRegex: (\S+)[^\[]+(\[[^:]+:\d+:\d+:\d+\s\S+)\s"(\w+)\s(\S+)\s([^"]+)"\s(\S+)\s(\d+)\s(\d+)\s(\d+)\s"([^"]+)"\s"([^"]+)"\s+(\S+)\s(\S+).*
beginningRegex: (\S+)[^\[]+(\[[^:]+:\d+:\d+:\d+\s\S+)\s"(\w+)\s(\S+)\s([^"]+)"\s(\S+)\s(\d+)\s(\d+)\s(\d+)\s"([^"]+)"\s"([^"]+)"\s+(\S+)\s(\S+).*
# 提取的key列表,与提取的value的一一对应
keys: ['remote_addr','time_local','request_method','request_url','http_protocol','http_host','status','request_length','body_bytes_sent','http_referer','http_user_agent','request_time','upstream_response_time']
采集到日志服务的数据为:
body_bytes_sent: 9703
http_host: 127.0.0.1
http_protocol: HTTP/1.1
http_referer: http://127.0.0.1/course/explore?filter%5Btype%5D=all&filter%5Bprice%5D=all&filter%5BcurrentLevelId%5D=all&orderBy=studentNum
http_user_agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0
remote_addr: 10.135.46.111
request_length: 782
request_method: GET
request_time: 0.354
request_url: /my/course/1
status: 200
time_local: [22/Jan/2019:19:19:30 +0800]
upstream_response_time: 0.354
多行-完全正则格式
多行-完全正则模式适用于日志文本中一条完整的日志数据跨占多行(例如 Java 程序日志),可按正则表达式提取为多个 key-value 键值的日志解析模式。若不需要提取 key-value,请参阅多行全文格式进行配置。假设一条日志原始数据为:
[2018-10-01T10:30:01,000] [INFO] java.lang.Exception: exception happened
at TestPrintStackTrace.f(TestPrintStackTrace.java:3)
at TestPrintStackTrace.g(TestPrintStackTrace.java:7)
at TestPrintStackTrace.main(TestPrintStackTrace.java:16)
LogConfig 配置的参考如下:
apiVersion: cls.cloud.tencent.com/v1
kind: LogConfig
spec:
clsDetail:
topicId: xxxxxx-xx-xx-xx-xxxxxxxx
#多行-完全正则格式
logType: multiline_fullregex_log
extractRule:
#行首完全正则表达式,只有以日期时间开头的行才被认为是新一条日志的开头,否则就添加换行符\n并追加到当前日志的尾部
beginningRegex: \[\d+-\d+-\w+:\d+:\d+,\d+\]\s\[\w+\]\s.*
#正则表达式,会根据()捕获组提取对应的value
logRegex: \[(\d+-\d+-\w+:\d+:\d+,\d+)\]\s\[(\w+)\]\s(.*)
# 提取的 key 列表,与提取的 value 的一一对应
keys:
- time
- level
- msg
根据提取的 key,采集到日志服务的数据为:
time:2018-10-01T10:30:01,000`
level:INFO`
msg:java.lang.Exception: exception happened
at TestPrintStackTrace.f(TestPrintStackTrace.java:3)
at TestPrintStackTrace.g(TestPrintStackTrace.java:7)
at TestPrintStackTrace.main(TestPrintStackTrace.java:16)
JSON 格式
JSON 格式日志会自动提取首层的 key 作为对应字段名,首层的 value 作为对应的字段值,以该方式将整条日志进行结构化处理,每条完整的日志以换行符\n为结束标识符。
{"remote_ip":"10.135.46.111","time_local":"22/Jan/2019:19:19:34 +0800","body_sent":23,"responsetime":0.232,"upstreamtime":"0.232","upstreamhost":"unix:/tmp/php-cgi.sock","http_host":"127.0.0.1","method":"POST","url":"/event/dispatch","request":"POST /event/dispatch HTTP/1.1","xff":"-","referer":"http://127.0.0.1/my/course/4","agent":"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0","response_code":"200"}
LogConfig配置的参考如下:
apiVersion: cls.cloud.tencent.com/v1
kind: LogConfig
spec:
clsDetail:
topicId: xxxxxx-xx-xx-xx-xxxxxxxx
# JSON格式日志
logType: json_log
采集到日志服务的数据为:
agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0
body_sent: 23
http_host: 127.0.0.1
method: POST
referer: http://127.0.0.1/my/course/4
remote_ip: 10.135.46.111
request: POST /event/dispatch HTTP/1.1
response_code: 200
responsetime: 0.232
time_local: 22/Jan/2019:19:19:34 +0800
upstreamhost: unix:/tmp/php-cgi.sock
upstreamtime: 0.232
url: /event/dispatch
xff: -
分隔符格式
分隔符日志是指一条日志数据可以根据指定的分隔符将整条日志进行结构化处理,每条完整的日志以换行符\n为结束标识符。日志服务在进行分隔符格式日志处理时,您需要为每个分开的字段定义唯一的 key。
10.20.20.10 ::: [Tue Jan 22 14:49:45 CST 2019 +0800] ::: GET /online/sample HTTP/1.1 ::: 127.0.0.1 ::: 200 ::: 647 ::: 35 ::: http://127.0.0.1/
LogConfig配置的参考如下:
apiVersion: cls.cloud.tencent.com/v1
kind: LogConfig
spec:
clsDetail:
topicId: xxxxxx-xx-xx-xx-xxxxxxxx
# 分隔符日志
logType: delimiter_log
extractRule:
# 分隔符
delimiter: ':::'
# 提取的key列表,与被分割的字段一一对应
keys: ['IP','time','request','host','status','length','bytes','referer']
采集到日志服务的数据为:
IP: 10.20.20.10
bytes: 35
host: 127.0.0.1
length: 647
referer: http://127.0.0.1/
request: GET /online/sample HTTP/1.1
status: 200
time: [Tue Jan 22 14:49:45 CST 2019 +0800]
日志源
容器标准输出 容器文件 主机文件
容器标准输出
示例1:采集default命名空间中的所有容器的标准输出
apiVersion: cls.cloud.tencent.com/v1
kind: LogConfig
spec:
inputDetail:
type: container_stdout
containerStdout:
namespace: default
allContainers: true
...
示例2: 采集production命名空间中属于ingress-gateway deployment的pod中的容器的标准输出
apiVersion: cls.cloud.tencent.com/v1
kind: LogConfig
spec:
inputDetail:
type: container_stdout
containerStdout:
allContainers: false
workloads:
- namespace: production
name: ingress-gateway
kind: deployment
...
示例3: 采集production命名空间中pod标签中包含“k8s-app=nginx”的pod中的容器的标准输出
apiVersion: cls.cloud.tencent.com/v1
kind: LogConfig
spec:
inputDetail:
type: container_stdout
containerStdout:
namespace: production
allContainers: false
includeLabels:
k8s-app: nginx
...
容器文件
示例1: 采集production命名空间中属于ingress-gateway deployment的pod中的nginx容器中/data/nginx/log/路径下名为access.log的文件
apiVersion: cls.cloud.tencent.com/v1
kind: LogConfig
spec:
topicId: xxxxxx-xx-xx-xx-xxxxxxxx
inputDetail:
type: container_file
containerFile:
namespace: production
workload:
name: ingress-gateway
type: deployment
container: nginx
logPath: /data/nginx/log
filePattern: access.log
...
示例2: 采集production命名空间中pod标签包含“k8s-app=ingress-gateway“的pod中的nginx容器中/data/nginx/log/路径下名为access.log的文件
apiVersion: cls.cloud.tencent.com/v1
kind: LogConfig
spec:
inputDetail:
type: container_file
containerFile:
namespace: production
includeLabels:
k8s-app: ingress-gateway
container: nginx
logPath: /data/nginx/log
filePattern: access.log
...
主机文件
示例: 采集主机/data/路径下所有.log文件
apiVersion: cls.cloud.tencent.com/v1
kind: LogConfig
spec:
inputDetail:
type: host_file
hostFile:
logPath: /data
filePattern: *.log
...
创建LogConfig对象
# kubectl create -f /usr/local/LogConfig.yaml
配置CLS鉴权ConfigMap
以Master节点路径/usr/local/为例:wget下载ConfigMap.yaml声明文件
# wget https://mirrors.tencent.com/install/cls/k8s/ConfigMap.yaml
注意:需将ConfigMap.yaml中的TmpSecretId以及TmpSecretKey的值配置为您的API密钥ID和API密钥KEY。
使用kubect创建ConfigMap对象。操作命令如下:
# kubectl create -f /usr/local/ConfigMap.yaml
部署Log-Provinsioner
Log-Provisioner负责发现并监听LogConfig资源中日志主题ID, 日志采集规则,日志文件路径,并同步至CLS侧。
以Master节点路径/usr/local/为例:wget下载Log-Provisioner.yaml声明文件
# wget https://mirrors.tencent.com/install/cls/k8s/Log-Provisioner.yaml
注意:需将Log-Provisioner.yaml中环境变量env下的CLS_HOST字段配置为目标日志主题所在地域的域名。不同地域的域名可参考资料中 [3]可用地域
使用kubect以Deployment的方式部署Log-Provinsioner。操作命令如下:
# kubectl create -f /usr/local/Log-Provinsioner.yaml
部署Log-Agent和Loglistener
Log-Agent负责拉取集群中LogConfig中的日志源信息,并计算容器日志在宿主机上映射的绝对路径。 Loglistener负责采集与解析宿主机日志文件路径下的日志文件,并上传至CLS侧
以Master节点路径/usr/local/为例:wget下载Log-Agent和Loglistener的声明文件
# wget https://mirrors.tencent.com/install/cls/k8s/Log—Agent.yaml
注意:如果宿主机的docker根目录不在/var/lib/docker(这是在宿主机的根目录)下,需要在Log—Agent.yaml声明文件中把docker的根目录映射到容器中,如下图,将/data/docker挂载到容器中。
使用kubect以DaemonSet的方式部署Log-Agent和Loglistener。操作命令如下:
# kubectl create -f /usr/local/Log—Agent.yaml
CLS控制台查看日志
至此, 就完成了集群日志采集的所有部署,您可以到 [5]CLS日志服务检索页查看采集上来的日志。
其他资料
[1] TKE开启日志采集:https://cloud.tencent.com/document/product/457/56751
[2] 创建日志主题:https://cloud.tencent.com/document/product/614/41035
[3] 可用地域:https://cloud.tencent.com/document/product/614/18940
[4] API密钥管理:https://console.cloud.tencent.com/cam/capi
[5] CLS 日志服务检索页:https://console.cloud.tencent.com/cls/search
[6] CLS 日志服务免费额度领取:https://cloud.tencent.com/document/product/614/47116
重 磅 来 袭
往期精选推荐